﻿using DevExpress.ExpressApp.DC;
using EasyXaf.LowCode.WorkflowEditors.Models;
using EasyXaf.LowCode.WorkflowEditors.Models.Activities;
using EasyXaf.LowCode.WorkflowEditors.UndoManagers;
using System.Xml.Linq;

namespace EasyXaf.LowCode.WorkflowEditors;

public static class WorkflowActions
{
    public static void ChangeNodeProperty<T>(this IUndoManager undoManager, string actionName, INode node, T oldValue, T newValue, Action<INode, T> setValue)
    {
        using (undoManager.CreateTransaction(actionName))
        {
            undoManager.Execute(new
            {
                node.Workflow,
                NodeId = node.Id,
                SetValue = setValue,
                OldValue = oldValue,
                NewValue = newValue
            }, state =>
            {
                var node = state.Workflow.FindNode(state.NodeId);
                setValue(node, state.NewValue);
                return new
                {
                    state.Workflow,
                    state.NodeId,
                    state.SetValue,
                    OldValue = state.NewValue,
                    NewValue = state.OldValue
                };
            });
        }
    }

    public static void ChangeNodeProperty<T>(this IUndoManager undoManager, string actionName, INode node, T oldValue, T newValue, IMemberInfo memberInfo)
    {
        using (undoManager.CreateTransaction(actionName))
        {
            undoManager.Execute(new
            {
                node.Workflow,
                NodeId = node.Id,
                OldValue = oldValue,
                NewValue = newValue,
                MemberInfo = memberInfo
            }, state =>
            {
                var node = state.Workflow.FindNode(state.NodeId);
                node.SetMemberValue(state.MemberInfo, state.NewValue);
                return new
                {
                    state.Workflow,
                    state.NodeId,
                    OldValue = state.NewValue,
                    NewValue = state.OldValue,
                    state.MemberInfo
                };
            });
        }
    }

    public static void ChangeNodeScale(this IUndoManager undoManager, INode node, double scale)
    {
        if (node.ViewMode == NodeViewMode.Title)
        {
            ChangeNodeProperty(undoManager, "更改节点大小", node, node.TitleViewScale, scale, (node, scale) => node.TitleViewScale = scale);
        }
        else
        {
            ChangeNodeProperty(undoManager, "更改节点大小", node, node.DetailViewScale, scale, (node, scale) => node.DetailViewScale = scale);
        }
    }

    public static void ChangeNodeViewMode(this IUndoManager undoManager, INode node, NodeViewMode viewMode)
    {
        ChangeNodeProperty(undoManager, "更改节点视图模式", node, node.ViewMode, viewMode, (node, viewMode) => node.ViewMode = viewMode);
    }

    public static void ChangeNodeCaption(this IUndoManager undoManager, INode node, string caption)
    {
        ChangeNodeProperty(undoManager, "更改节点标题", node, node.Caption, caption, (node, caption) => node.Caption = caption);
    }

    public static void ChangeNodeComment(this IUndoManager undoManager, INode node, string comment)
    {
        ChangeNodeProperty(undoManager, "更改节点备注", node, node.Comment, comment, (node, comment) => node.Comment = comment);
    }

    public static void ChangeCurrentContainer(this IUndoManager undoManager, IWorkflow workflow, IContainer container)
    {
        using (undoManager.CreateTransaction("更改当前容器"))
        {
            undoManager.Execute(new
            {
                Workflow = workflow,
                ContainerId = container.Id
            }, state =>
            {
                var containerId = state.Workflow.CurrentContainer.Id;
                state.Workflow.ChangeCurrentContainer(state.ContainerId);
                return new
                {
                    state.Workflow,
                    ContainerId = containerId
                };
            });
        }
    }

    public static void ChangeActivityIndex(this IUndoManager undoManager, IActivity activity, Func<int, int> changeIndex)
    {
        var index = activity.Sequence.Activities.IndexOf(activity);
        index = changeIndex(index);

        using (undoManager.CreateTransaction("更改活动顺序"))
        {
            undoManager.Execute(new
            {
                activity.Workflow,
                ActivityId = activity.Id,
                ActivityIndex = index
            }, state =>
            {
                var activity = state.Workflow.FindActivity(state.ActivityId);
                var index = activity.Sequence.Activities.IndexOf(activity);
                activity.Sequence.Activities.Move(index, state.ActivityIndex);
                return new
                {
                    state.Workflow,
                    state.ActivityId,
                    ActivityIndex = index
                };
            });
        }
    }

    public static void ChangeActivityCollapseState(this IUndoManager undoManager, IBranchesActivity branchesActivity, bool isCollapse)
    {
        using (undoManager.CreateTransaction(isCollapse ? "折叠活动" : "展开活动"))
        {
            undoManager.Execute(new
            {
                branchesActivity.Workflow,
                BranchesActivityId = branchesActivity.Id,
                IsCollapse = isCollapse,
            }, state =>
            {
                var branchesActivity = (IBranchesActivity)state.Workflow.FindActivity(state.BranchesActivityId);
                branchesActivity.IsCollapse = state.IsCollapse;
                return new
                {
                    state.Workflow,
                    state.BranchesActivityId,
                    IsCollapse = !state.IsCollapse,
                };
            });
        }
    }

    public static void ChangeBranchIndex(this IUndoManager undoManager, IBranch branch, Func<int, int> changeIndex)
    {
        var index = ((IBranchesActivity)branch.Activity).Branches.IndexOf(branch);
        index = changeIndex(index);

        using (undoManager.CreateTransaction("更改分支顺序"))
        {
            undoManager.Execute(new
            {
                ((INode)branch).Workflow,
                BranchId = branch.Id,
                BranchIndex = index
            }, state =>
            {
                var branch = (IBranch)state.Workflow.FindSequence(state.BranchId);
                var index = ((IBranchesActivity)branch.Activity).Branches.IndexOf(branch);
                ((IBranchesActivity)branch.Activity).Branches.Move(index, state.BranchIndex);
                return new
                {
                    state.Workflow,
                    state.BranchId,
                    BranchIndex = index
                };
            });
        }
    }

    public static void AddActivity(this IUndoManager undoManager, IActivity activity, ISequence sequence, int index)
    {
        using (undoManager.CreateTransaction("添加活动"))
        {
            undoManager.Execute(new
            {
                sequence.Workflow,
                SequenceId = sequence.Id,
                ActivityXml = activity.ToXml(),
                ActivityIndex = index
            }, state =>
            {
                var sequence = state.Workflow.FindSequence(state.SequenceId);
                var element = XElement.Parse(state.ActivityXml);
                var activity = state.Workflow.CreateActivityFromXml(element, sequence);
                sequence.Activities.Insert(state.ActivityIndex, activity);
                return new
                {
                    state.Workflow,
                    state.SequenceId,
                    state.ActivityXml,
                    state.ActivityIndex
                };
            }, state =>
            {
                var sequence = state.Workflow.FindSequence(state.SequenceId);
                sequence.Activities.RemoveAt(state.ActivityIndex);
                return new
                {
                    state.Workflow,
                    state.SequenceId,
                    state.ActivityXml,
                    state.ActivityIndex
                };
            });
        }
    }

    public static void DeleteActivity(this IUndoManager undoManager, IActivity activity)
    {
        using (undoManager.CreateTransaction("删除活动"))
        {
            undoManager.Execute(new
            {
                activity.Workflow,
                SequenceId = activity.Sequence.Id,
                ActivityXml = activity.ToXml(),
                ActivityIndex = activity.Sequence.Activities.IndexOf(activity)
            }, state =>
            {
                var sequence = state.Workflow.FindSequence(state.SequenceId);
                sequence.Activities.RemoveAt(state.ActivityIndex);
                return new
                {
                    state.Workflow,
                    state.SequenceId,
                    state.ActivityXml,
                    state.ActivityIndex
                };
            }, state =>
            {
                var sequence = state.Workflow.FindSequence(state.SequenceId);
                var element = XElement.Parse(state.ActivityXml);
                var activity = state.Workflow.CreateActivityFromXml(element, sequence);
                sequence.Activities.Insert(state.ActivityIndex, activity);
                return new
                {
                    state.Workflow,
                    state.SequenceId,
                    state.ActivityXml,
                    state.ActivityIndex
                };
            });
        }
    }

    public static void AddBranch(this IUndoManager undoManager, IBranch branch, IBranchesActivity branchesActivity, int index)
    {
        using (undoManager.CreateTransaction("添加分支"))
        {
            undoManager.Execute(new
            {
                branchesActivity.Workflow,
                BranchesActivityId = branchesActivity.Id,
                BranchXml = branch.ToXml(),
                BranchIndex = index
            }, state =>
            {
                var branchesActivity = (IBranchesActivity)state.Workflow.FindActivity(state.BranchesActivityId);
                var element = XElement.Parse(state.BranchXml);
                var branch = state.Workflow.CreateBranchFromXml(element, branchesActivity);
                branchesActivity.Branches.Insert(state.BranchIndex, branch);
                return new
                {
                    state.Workflow,
                    state.BranchesActivityId,
                    state.BranchXml,
                    state.BranchIndex
                };
            }, state =>
            {
                var branchesActivity = (IBranchesActivity)state.Workflow.FindActivity(state.BranchesActivityId);
                branchesActivity.Branches.RemoveAt(state.BranchIndex);
                return new
                {
                    state.Workflow,
                    state.BranchesActivityId,
                    state.BranchXml,
                    state.BranchIndex
                };
            });
        }
    }

    public static void DeleteBranch(this IUndoManager undoManager, IBranch branch)
    {
        using (undoManager.CreateTransaction("删除分支"))
        {
            undoManager.Execute(new
            {
                ((IBranchesActivity)branch.Activity).Workflow,
                BranchesActivityId = ((IBranchesActivity)branch.Activity).Id,
                BranchXml = branch.ToXml(),
                BranchIndex = ((IBranchesActivity)branch.Activity).Branches.IndexOf(branch)
            }, state =>
            {
                var branchesActivity = (IBranchesActivity)state.Workflow.FindActivity(state.BranchesActivityId);
                branchesActivity.Branches.RemoveAt(state.BranchIndex);
                return new
                {
                    state.Workflow,
                    state.BranchesActivityId,
                    state.BranchXml,
                    state.BranchIndex
                };
            }, state =>
            {
                var branchesActivity = (IBranchesActivity)state.Workflow.FindActivity(state.BranchesActivityId);
                var element = XElement.Parse(state.BranchXml);
                var branch = state.Workflow.CreateBranchFromXml(element, branchesActivity);
                branchesActivity.Branches.Insert(state.BranchIndex, branch);
                return new
                {
                    state.Workflow,
                    state.BranchesActivityId,
                    state.BranchXml,
                    state.BranchIndex
                };
            });
        }
    }
}
